package com.zy.core.common.security.entity;

import com.zy.core.common.constant.enums.StatusEnum;
import com.zy.core.common.exception.user.UserNotExistsException;
import com.zy.project.system.permission.entity.SystemPermission;
import com.zy.project.system.role.entity.SystemRole;
import com.zy.project.system.role.manager.SystemRoleManager;
import com.zy.project.system.user.entity.SystemUser;
import com.zy.project.system.user.manager.SystemUserManager;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import java.util.HashSet;
import java.util.Set;

/**
 * 权限相关校验
 * Package: core.service
 * <p>
 * Description： TODO
 * <p>
 * Author: zhangyu
 * <p>
 * Date: Created in 2018-9-2 11:07
 * <p>
 * Company: mingtu
 * <p>
 * Copyright: Copyright (c) 2018
 * <p>
 * Version: 0.0.1
 * <p>
 * Modified By:
 */
@Component
public class UserRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private SystemUserManager userManager;

    @Autowired
    private SystemRoleManager systemRoleManager;

    @Autowired
    HashedCredentialsMatcher matcherl;

    /**
     * 授权,获取数据库中的权限和角色
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        super.setCredentialsMatcher(matcherl);
        logger.info("---------------- 执行 Shiro 权限获取 ---------------------");
        //String userId = ShiroUtils.getUserId();
        String username= (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        SystemUser user = userManager.findByUsername(username);
        Set<SystemRole> roles = user.getRoles();
        Set<String> roleStrs = new HashSet<>();
        Set<String> permissionStrs = new HashSet<>();
        roles.forEach(role -> {
            roleStrs.add(role.getRoleName());
            Set<SystemPermission> permissions = role.getPermissions();
            permissions.forEach(permission -> {
                permissionStrs.add(permission.getName());
            });
        });
        // 角色加入AuthorizationInfo认证对象
        info.setRoles(roleStrs);
        // 权限加入AuthorizationInfo认证对象
        info.setStringPermissions(permissionStrs);
        logger.info("----["+ user.getUsername() +"]获取到以下权限 ----");
        logger.info("["+info.getStringPermissions().toString()+"]");
        logger.info("---------------- Shiro 权限获取成功 ----------------------");
        return info;
    }

    /**
     * 身份验证并且登录
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        super.setCredentialsMatcher(matcherl);
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        String password = "";
        if(upToken.getPassword() != null){
            password = new String(upToken.getPassword());
        }
        SystemUser user = userManager.findByUsername(username);

        //验证用户是否存在
        if(user == null){
            throw new UserNotExistsException();
        }

        if(user.getStatus().getValue() == StatusEnum.Inactive.getValue()){
            throw new LockedAccountException("用户已被禁用");
        }


        //验证成功
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                user, //用户名
                user.getPassword(),//密码
                ByteSource.Util.bytes(user.getCredentialsSalt()),//username+slat证书
                getName()  //realm name
        );
        //用户信息写入session
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("userSession", user);
        //session.setAttribute("userSessionId", user.getId());
        return info;
    }
    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo(){
        logger.info("清除缓存....");
        PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
        super.clearCachedAuthorizationInfo(principals);
    }

}
